package com.zt.fbg.filter;


import com.alibaba.fastjson.JSON;
import com.zt.fbg.utils.Result;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtParser;
import io.jsonwebtoken.Jwts;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Base64Utils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.spec.InvalidKeySpecException;
import java.util.List;

/**
 * jwt 拦截解析
 *
 * @author carl
 * @date 2020/11/06 18:26
 **/
@Component
@ConfigurationProperties(prefix = "secure.ignored")
public class JwtAuthFilter implements GlobalFilter, Ordered {

    private final Logger log = LoggerFactory.getLogger(JwtAuthFilter.class);
    @Autowired
    private JwtParser jwtParser;
//@Value("${publicKey}")
//private String publicKey;
    /**
     * 不拦截的urls
     */
    private List<String> urls;

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String url = exchange.getRequest().getURI().getPath();
        // 放行请求的情况下，token 为空，允许继续请求，白名单就是在这里的
        if (pathMatcher(url)) {
            return chain.filter(exchange);
        }

        //获取token
        String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StringUtils.isBlank(token)) {
            return response(exchange, Result.error(HttpStatus.UNAUTHORIZED.value(), "【网关】请登陆获取token"));
        }
        if (!StringUtils.startsWith(token,"Bearer ")) {
            return response(exchange, Result.error(HttpStatus.UNAUTHORIZED.value(), "【网关】缺少Bearer 前缀"));
        }
        try {
            checkToken(StringUtils.removeStart(token,"Bearer "));
            exchange.getRequest().mutate().header(HttpHeaders.AUTHORIZATION,new String[]{token});
            return chain.filter(exchange);
        } catch (ExpiredJwtException e) {
            log.error(e.getMessage(), e);
            return response(exchange, Result.error(HttpStatus.UNAUTHORIZED.value(), "【网关】认证过期"));
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            return response(exchange, Result.error(HttpStatus.UNAUTHORIZED.value(), "【网关】认证失败"));
        }

    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE + 1;
    }
    /**
     * 请求输出
     * @author carl
     * @date 2020/11/06 18:17
     * @param exchange
     * @param object
     * @return reactor.core.publisher.Mono<java.lang.Void>
     */
    private Mono<Void> response(ServerWebExchange exchange, Object object) {
        String json = JSON.toJSONString(object);
        DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(json.getBytes(StandardCharsets.UTF_8));
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON_UTF8);
        exchange.getResponse().setStatusCode(HttpStatus.OK);
        return exchange.getResponse().writeWith(Flux.just(buffer));
    }


    private void checkToken(String jwtToken) throws NoSuchAlgorithmException, InvalidKeySpecException {
//        PublicKey key = SecureUtil.generatePublicKey("RSA", Base64Utils.decode(publicKey.getBytes()));
//        Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody();
      Claims claims = jwtParser.parseClaimsJws(jwtToken).getBody();
    }

    private boolean pathMatcher(String requestUri) {
        for (String url : urls) {
            if (antPathMatcher.match(url, requestUri)) {
                return true;
            }
        }
        return false;
    }

    public List<String> getUrls() {
        return urls;
    }

    public void setUrls(List<String> urls) {
        this.urls = urls;
    }


}
